<?php
namespace backend\widgets;

use backend\controllers\BaseController;
use common\models\User;
use Yii;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\widgets\Menu;

class AdminMenu extends Menu
{
    public $menuRoute;

    public $collapse = true;

    public function init()
    {
        parent::init();
        $i = 0;
        foreach ($this->items as $group => &$item) {
            if (is_array($item)) {
                if (!isset($item['priority'])) {
                    $item['priority'] = $i++;
                } else {
                    $i = (int)$item['priority'];
                }
            } else {
                unset($this->items[$group]);
                $this->items[(string)$item . ++$i] = ['priority' => $i];
            }
        }
    }

    public function run()
    {
        if ($this->route === null && Yii::$app->controller !== null) {
            $this->route = Yii::$app->controller->getRoute();
            if (!isset(Yii::$app->controller->menuRoute)) {
                $this->menuRoute = '/' . Yii::$app->controller->getUniqueId() . '/' .
                    Yii::$app->controller->defaultAction;
            } else {
                $this->menuRoute = Yii::$app->controller->menuRoute;
            }
        }

        if ($this->params === null) {
            $this->params = Yii::$app->request->getQueryParams();
        }

        uasort($this->items, function ($a, $b) {
            if (is_array($a) && isset($a['priority'])) {
                $ap = $a['priority'];
            } else {
                $ap = 0;
            }

            if (is_array($b) && isset($b['priority'])) {
                $bp = $b['priority'];
            } else {
                $bp = 0;
            }

            return $ap < $bp ? -1 : 1;
        });

        $items = $this->filterItems($this->items);
        $i = 0;
        $hasMenu = false;
        $count = count($items);
        $output = Html::beginTag('ul', ['class' => 'nav', 'role' => 'navigation']);
        foreach ($items as $group => $item) {
            if (++$i !== $count && $group[0] === '_') {
                $output .= Html::endTag('ul');
                $output .= Html::beginTag('ul', ['class' => 'nav', 'role' => 'navigation']);
            } elseif ($group[0] !== '_') {
                $hasMenu = true;
                $output .= $this->renderTopItem($item);
            }
        }
        $output .= Html::endTag('ul');
        $output .= $this->renderCollapse();
        if ($hasMenu) {
            return $output;
        } else {
            return '';
        }
    }

    protected function renderTopItem($topItem)
    {
        $classes = array('top-menu');
        $isCurrent = false;
        $renderItems = '';

        if (isset($topItem['items']) && is_array($topItem['items']) && $topItem['items']) {
            array_push($classes, 'has-sub');
            $items = $this->normalizeItems($topItem['items'], $isCurrent);
            $items = $this->filterItems($items);
            foreach ($items as $i => $item) {
                if (isset($item['callback']) && is_callable($item['callback'])) {
                    $items[$i] = call_user_func($item['callback'], $item);
                }
            }
            $options = $this->options;
            Html::addCssClass($options, 'sub-nav');
            $tag = ArrayHelper::remove($options, 'tag', 'ul');
            $renderItems = Html::tag($tag, $this->renderItems($items), $options);
        } elseif ($this->isItemActive($topItem)) {
            $isCurrent = true;
        }

        array_push($classes, $isCurrent ? 'current-menu' : 'not-current-menu');

        $title = '';
        if (isset($topItem['icon'])) {
            if (($pos = strpos($topItem['icon'], '-')) !== false) {
                $iconPrefix = substr($topItem['icon'], 0, $pos);
                $iconName = substr($topItem['icon'], $pos + 1);
            } else {
                $iconPrefix = '';
                $iconName = $topItem['icon'];
            }

            switch ($iconPrefix) {
                case 'glyph':
                    $iconClass = "glyphicon glyphicon-" . $iconName;
                    break;
                case 'dash':
                    $iconClass = "dashicons dashicons-" . $iconName;
                    break;
                case 'fa':
                    $iconClass = "fa fa-" . $iconName;
                    break;
                default:
                    $iconClass = $iconName;
            }

            $title = '<span class="menu-icon ' . $iconClass . '"></span> ';
        }

        if (isset($topItem['callback']) && is_callable($topItem['callback'])) {
            $topItem = call_user_func($topItem['callback'], $topItem);
        }

        if (!isset($topItem['url'])) {
            $topItem['url'] = '#';
        }

        $encodeLabel = isset($topItem['encode']) ? $topItem['encode'] : $this->encodeLabels;

        if (isset($topItem['label'])) {
            $topItem['label'] = $encodeLabel ? Html::encode($topItem['label']) : $topItem['label'];
        } else {
            $topItem['label'] = '-';
        }

        $title .= '<span class="menu-name">' . $topItem['label'] . '</span>';

        return strtr('<li class="{class}">{link} {items}</li>', array(
            '{class}' => implode(' ', $classes),
            '{link}' => Html::a($title, $topItem['url']),
            '{items}' => $renderItems,
        ));
    }

    protected function renderCollapse()
    {
        if (empty($this->collapse)) {
            return '';
        }

        return <<<EOT
    <button id="collapse-menu" type="button">
    <span class="dashicons dashicons-admin-collapse"></span>
    <span class="collapse-tip">收起菜单</span>
    </button>
EOT;
    }

    /**
     * @param array $items
     * @return array
     */
    protected function filterItems($items)
    {
        $user = Yii::$app->getUser();
        if ($user->getId() != User::ROOT_ID) {
            foreach ($items as $index => $item) {
                if (isset($item['url']) && is_array($item['url']) && isset($item['url'][0])) {
                    $route = $item['url'][0];
                    $params = array_slice($item['url'], 1);

                    if (Yii::$app->controller && Yii::$app->controller instanceof BaseController) {
                        if (!Yii::$app->controller->canAccessByRoute($route, $params)) {
                            unset($items[$index]);
                        }
                    }

                    if (isset($item['items'])) {
                        $item['items'] = $this->filterItems($item['items']);
                    }
                }
            }
        }
        return $items;
    }

    protected function isItemActive($item)
    {
        if (isset($item['url']) && is_array($item['url']) && isset($item['url'][0])) {
            $route = $item['url'][0];
            if ($route[0] !== '/' && Yii::$app->controller) {
                $route = Yii::$app->controller->module->getUniqueId() . '/' . $route;
            }
            if (ltrim($route, '/') !== $this->route) {
                if ($route === $this->menuRoute) {
                    return true;
                }
                return false;
            }
            unset($item['url']['#']);
            if (count($item['url']) > 1) {
                foreach (array_splice($item['url'], 1) as $name => $value) {
                    if ($value !== null && (!isset($this->params[$name]) || $this->params[$name] != $value)) {
                        return false;
                    }
                }
            }

            return true;
        }

        return false;
    }
}
